package cn.schoolwow.quickdao.module.database.dml.instance.service.compare;

import cn.schoolwow.quickdao.domain.database.dml.CompareInstanceListResult;
import cn.schoolwow.quickdao.domain.database.dml.UpdateType;
import cn.schoolwow.quickdao.domain.entity.Entity;
import cn.schoolwow.quickdao.module.database.dml.common.domain.ManipulationOption;
import cn.schoolwow.quickdao.module.database.dml.instance.flow.common.SetInstanceEntityFlow;
import cn.schoolwow.quickdao.module.database.dml.instance.flow.common.SetInstanceUniqueTypeFlow;
import cn.schoolwow.quickdao.module.database.dml.instance.flow.insert.get.DistinguishExistInstanceFlow;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.util.domain.query.instanceList.QueryInstanceList;
import org.apache.commons.lang3.Validate;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class CompareInstanceListFlow<T> implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        setCompareInstanceListResult(flowContext);
        setDeleteInstanceList(flowContext);
    }

    @Override
    public String name() {
        return "比较实例列表流程";
    }

    private void setCompareInstanceListResult(FlowContext flowContext){
        Collection<T> currentInstances = (Collection<T>) flowContext.getData("currentInstances");

        CompareInstanceListResult<T> compareInstanceListResult = new CompareInstanceListResult();
        flowContext.putInstanceData(compareInstanceListResult);

        if(null!=currentInstances&&!currentInstances.isEmpty()){
            flowContext.startFlow(new SetInstanceEntityFlow())
                    .next(new DistinguishExistInstanceFlow())
                    .putTemporaryData("instances", currentInstances.toArray(new Object[0]))
                    .execute();
            compareInstanceListResult.insertInstanceList = (List<T>) flowContext.getData("notExistInstanceList");
            compareInstanceListResult.updateInstanceList = (List<T>) flowContext.getData("existInstanceList");
        }
    }

    private void setDeleteInstanceList(FlowContext flowContext){
        Collection<T> totalInstances = (Collection<T>) flowContext.getData("totalInstances");
        if(null==totalInstances||totalInstances.isEmpty()){
            return;
        }
        if(!flowContext.containKey("entity")){
            flowContext.startFlow(new SetInstanceEntityFlow())
                    .putTemporaryData("instances", totalInstances.toArray(new Object[0]))
                    .execute();
        }

        ManipulationOption manipulationOption = flowContext.checkInstanceData(ManipulationOption.class);
        Entity entity = flowContext.checkData("entity", Entity.class);

        flowContext.executeFlowList(new SetInstanceUniqueTypeFlow());
        UpdateType updateType = flowContext.checkInstanceData(UpdateType.class);
        switch (updateType){
            case UpdateByUniqueFieldName:{
                setDeleteInstanceListByFieldNameList(manipulationOption.uniqueFieldNames, flowContext);
            }break;
            case UpdateByUniqueKey:{
                List<String> fieldNames = QueryInstanceList.newQuery(entity.uniqueProperties)
                        .execute()
                        .getSingleFieldValueList("name");
                setDeleteInstanceListByFieldNameList(fieldNames, flowContext);
            }break;
            case UpdateById:{
                setDeleteInstanceListByFieldNameList(Arrays.asList(entity.id.name), flowContext);
            }break;
        }
    }

    private void setDeleteInstanceListByFieldNameList(Collection<String> fieldNames, FlowContext flowContext){
        Collection<T> currentInstances = (Collection<T>) flowContext.getData("currentInstances");
        Collection<T> totalInstances = (Collection<T>) flowContext.getData("totalInstances");
        CompareInstanceListResult<T> compareInstanceListResult = flowContext.checkInstanceData(CompareInstanceListResult.class);

        if(null==currentInstances&&null==totalInstances){
            return;
        }
        if(null==currentInstances){
            compareInstanceListResult.deleteInstanceList = totalInstances.stream().collect(Collectors.toList());
        }
        if(null==totalInstances){
            compareInstanceListResult.insertInstanceList = currentInstances.stream().collect(Collectors.toList());
        }

        List list = QueryInstanceList.newQuery(currentInstances)
                .execute()
                .getMultipleFieldValueList(fieldNames);
        compareInstanceListResult.deleteInstanceList = QueryInstanceList.newQuery(totalInstances)
                .addNotInQuery(fieldNames, list)
                .execute()
                .getList();
    }
}
